/*
 *         (C) COPYRIGHT NBI Limited
 *              ALL RIGHT RESERVED
 *
 * File        : fastflow/core/status.h
 * Authors     : dzhang
 * Create Time : 2021/09/04 19:06:42
 * Description :
 *
 */

#ifndef __FASTFLOW_CORE_STATUS_H___
#define __FASTFLOW_CORE_STATUS_H___

#include <memory>
#include <string>
#include "fastflow/core/ml_status.h"

namespace fastflow {


enum StatusCategory {
  NONE = 0,
  SYSTEM = 1,
  FASTFLOW = 2,
};

/**
   Error code for ONNXRuntime.
*/
enum StatusCode {
  OK = static_cast<unsigned int>(MLStatus::OK),
  FAIL = static_cast<unsigned int>(MLStatus::FAIL),
  INVALID_ARGUMENT = static_cast<unsigned int>(MLStatus::INVALID_ARGUMENT),
  NO_SUCHFILE = static_cast<unsigned int>(MLStatus::NO_SUCHFILE),
  NO_MODEL = static_cast<unsigned int>(MLStatus::NO_MODEL),
  ENGINE_ERROR = static_cast<unsigned int>(MLStatus::ENGINE_ERROR),
  RUNTIME_EXCEPTION = static_cast<unsigned int>(MLStatus::RUNTIME_EXCEPTION),
  INVALID_PROTOBUF = static_cast<unsigned int>(MLStatus::INVALID_PROTOBUF),
  MODEL_LOADED = static_cast<unsigned int>(MLStatus::MODEL_LOADED),
  NOT_IMPLEMENTED = static_cast<unsigned int>(MLStatus::NOT_IMPLEMENTED),
  INVALID_GRAPH = static_cast<unsigned int>(MLStatus::INVALID_GRAPH),
  SHAPE_INFERENCE_NOT_REGISTERED = static_cast<unsigned int>(MLStatus::SHAPE_INFERENCE_NOT_REGISTERED),
  REQUIREMENT_NOT_REGISTERED = static_cast<unsigned int>(MLStatus::REQUIREMENT_NOT_REGISTERED),
};

class Status {
public:
    Status() noexcept {}

    Status(StatusCategory category, int code, const std::string& msg);

    Status(StatusCategory category, int code);

    Status(const Status& other) {
        *this = other;
    }

    void operator=(const Status& other) {
        if (&other != this) {
            if (nullptr == other.state_) {
                state_.reset();
            } else if (state_ != other.state_) {
                state_.reset(new State(*other.state_));
            }
        }
    }

    Status(Status&&) = default;
    Status& operator=(Status&&) = default;
    ~Status() = default;

    bool IsOK() const noexcept;

    int Code() const noexcept;

    StatusCategory Category() const noexcept;

    const std::string& ErrorMessage() const;

    std::string ToString() const;

    bool operator==(const Status& other) const {
        return (this->state_ == other.state_) || (ToString() == other.ToString());
    }

    bool operator!=(const Status& other) const {
        return !(*this == other);
    }

    static const Status& OK() noexcept;

private:
    struct State {
        State(StatusCategory cat_, int code_, const std::string& msg_) : category(cat_), code(code_), msg(msg_) {}

        StatusCategory category = StatusCategory::NONE;
        int code = 0;
        std::string msg;
    };

    static const std::string& EmptyString();

    // state_ == nullptr when if status code is OK.
    std::unique_ptr<State> state_;
};

inline std::ostream& operator<<(std::ostream& out, const Status& status) {
    return out << status.ToString();
}

}  // namespace fastflow

#endif  // __FASTFLOW_CORE_STATUS_H___